/*********************************************************************************
 *      Copyright:  (C) 2021 ljl
 *                  All rights reserved.
 *
 *       Filename:  client.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(2021年12月13日)
 *         Author:  Li Jiale <244871365@qq.com>
 *      ChangeLog:  1, Release initial version on "2021年12月13日 19时09分17秒"
 *                 
 ********************************************************************************/

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <time.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <syslog.h>
#include <unistd.h>
#include <getopt.h>
#include <libgen.h>
#include "ds38b20.h"
#include "sqlite_db.h"
#include "cJSON.h"


#define  C_DB    "waitsend.db"

/*  
typedef struct sample_data_s 
{
    float               temp;
    char                time[32];
    char                ID[16];
} temp_data_t; 
*/

int g_sigalarm = 1;
int g_sigstop = 0;

void signal_act(int sig);
void signal_ign(int sig);
void signal_user(int signum);
int socket_connect(char *serv_ip, int serv_port);
void get_time(char *time, int size);
int create_cjson(char *buf, int bytes,  temp_data_t *data);
int socket_send_data(int confd, temp_data_t *data);
void print_usage(char *progname);

int main(int argc,char **argv)
{
    int                 opt;
    int                 sleep_time;
    char                *progname = NULL;
    int                 confd = 0;
    int                 serv_port = 0;
    char                *serv_ip = NULL;
    int                 rv = -1;
    int                 i = 0;
    char                time[64];
    char                temper[64];
    char                send_buf[128];
    int                 count = 0;

    temp_data_t         data;

    struct option       long_options[]={
        {"port",required_argument,NULL,'p'},
        {"serv_ip",required_argument,NULL,'i'},
        {"sleep_timetime",required_argument,NULL,'t'},
        {"help",no_argument,NULL,'h'},
        {NULL,0,NULL,0}
    };

    progname = basename(argv[0]);
    
    memset(data.ID, 0, sizeof(data.ID));
    snprintf(data.ID, sizeof(data.ID), "RPI001");

    while((opt = getopt_long(argc,argv,"p:i:t:h",long_options,NULL))!=-1)
    {
        switch(opt)
        {
             case'p':
                 serv_port = atoi(optarg);
                 break;
             case'i':
                 serv_ip = optarg;
                 break;
             case't':
                 sleep_time = atoi(optarg);
                 break;
             case'h':
                 print_usage(progname);
                 return EXIT_SUCCESS;

             default:
                 break;
        }
    }
    
    if(!serv_port || !serv_ip || !sleep_time)
    {
        print_usage(progname);
        return -1;
    }

    signal_act(SIGUSR1);
    signal_act(SIGALRM);
    signal_ign(SIGPIPE);
    
    if( init_db(C_DB) < 0 )
    {
        //log_err("SQLITE3 database initialize failed\n");
        printf("SQLITE3 database initialize failed\n");
        return -2;
    }

    //daemon(0,0);
    //openlog("client",LOG_CONS | LOG_PID,0);

    while( !g_sigstop )
    {
        if( !confd )
        {
            confd = socket_connect(serv_ip, serv_port);

            if( confd < 0 )
            {
                confd = 0;
            }
        }

        if( g_sigalarm )
        {
            g_sigalarm = 0;

            alarm(sleep_time);
            
            memset(&data.temp,0,sizeof(data.temp));
            memset(&data.time,0,sizeof(data.time));

            if( ds18b20_get_temperature(&data.temp) < 0 )
            {
                //log_err("ERROR: DS18b20 get temperature failure\n");
                printf("ERROR: DS18b20 get temperature failure\n");
                goto NEXT;
            }
            get_time(data.time, sizeof(data.time));
            
            if( !confd )
            {
                push_db(&data, sizeof(data));
                goto NEXT;
            }
                
            if( socket_send_data(confd,&data) < 0 )
            {
                push_db(&data, sizeof(data));
                close(confd);
                confd = 0;
                goto NEXT;
            }
            
        }

        if( confd )
        {
            printf("1\n");
            count = count_db();
            printf("%d\n",count);

            if( count <= 0 )
            {
                printf("next\n");
                goto NEXT;
            }
            else if( count > 10 )
            {
                count = 10;
            }

            for(i=0; i<count; i++)
            {
                pop_db(&data, sizeof(data));
                
                if( socket_send_data(confd, &data) < 0 )
                {
                    close(confd);
                    confd = 0;
                    break;
                }
                del_first_db();
                
                sleep(1);
            }
        }


NEXT:
        sleep(1);
    }

    close(confd);
    term_db();

    return 0;
}

void signal_act(int sig)
{
    struct sigaction    sigact;

    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigact.sa_handler = signal_user;
    sigaction(sig,&sigact,0);

    return;
}

void signal_ign(int sig)
{
    struct sigaction    sigign;

    sigemptyset(&sigign.sa_mask);
    sigign.sa_flags = 0;
    sigign.sa_handler = SIG_IGN;
    sigaction(sig, &sigign, 0);
    
    return;
}

void signal_user(int signum)
{
    if(signum == SIGUSR1)
    {   
        syslog(LOG_EMERG,"client is closed process exit\n");
        closelog();
        exit(0);
    }

    if(signum == SIGALRM)
    {
        g_sigalarm = 1;
    }
}

void print_usage(char *progname)
{
    printf("Usage: %s [OPTION]...\n", progname);
    printf(" %s is a socket server program, which used to get temperature to send to server\n",progname);
    printf("\nMandatory arguments to long options are mandatory for short options too:\n");

    printf(" -t[time] set get temperature sleep_time\n");
    printf(" -p[port ] Socket server port address\n");
    printf(" -i[ip ] Socket server ip address\n");
    printf(" -h[help ] Display this help information\n");
}

int socket_connect(char *serv_ip, int serv_port)
{
    int                     confd;
    struct sockaddr_in      serv_addr;

    confd = socket(AF_INET,SOCK_STREAM,0);
    if( confd < 0 )
    {
        //log_err("ERROR: client creat socket failure\n");
        printf("ERROR: client creat socket failure\n");
        return -1;
    }

    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(serv_port);
    inet_aton(serv_ip,&serv_addr.sin_addr);

    if( connect(confd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0 )
    {
        close(confd);
        //log_err("ERROR: client connect socket failure\n");
        printf("ERROR: client connect socket failure\n");
        return -2;
    }

    return confd;
}

void get_time(char *ptime, int size)
{
    char                *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
    time_t              timep;
    struct tm           *p;

    time(&timep);

    p = localtime(&timep);

    snprintf(ptime,size,"%d-%d-%d %d:%d:%d",(1900+p->tm_year), (1+p->tm_mon), p->tm_mday,(p->tm_hour)+8, p->tm_min, p->tm_sec);
}

int create_cjson(char *buf, int bytes,  temp_data_t *data)
{
    cJSON       *id;
    cJSON       *time;
    cJSON       *temper;
    int         rv = 0;
    char        btemp[32];


    memset(btemp, 0, sizeof(btemp));

    cJSON *monitor = cJSON_CreateObject();
    if(monitor == NULL)
    {
        return -1;
    }

    id = cJSON_CreateString(data->ID);
    cJSON_AddItemToObject(monitor, "id", id);

    time = cJSON_CreateString(data->time);
    cJSON_AddItemToObject(monitor, "tiem", time);
        
    snprintf(btemp, sizeof(btemp), "%.3f",  (data->temp));


    temper = cJSON_CreateString(btemp);
    cJSON_AddItemToObject(monitor, "temperature", temper);

    if(id == NULL || time == NULL || temper == NULL)
    {
        rv = -2;
        printf("client cjson NULL\n");
        goto end;                             
    }

    memcpy(buf, cJSON_Print(monitor), bytes);
    printf("%s\n",buf);

end:
    cJSON_Delete(monitor);
    
    return rv;
}

int socket_send_data(int confd, temp_data_t *data)
{
    int             rv = 0;
    char            buf[256];
    
    memset(buf,0,sizeof(buf));

    if( !confd || !data )
    {
        //log_err("ERROR: Invalid input arguments\n");
        printf("ERROR: Invalid input arguments\n");
        return -1;
    }
   
    rv = create_cjson(buf, sizeof(buf), data);

    if( rv < 0 )
    {
        //log_err("ERROR: create cjson failure\n");
        printf("ERROR: create cjson failure\n");
        return -2;
    }

    if( write(confd, buf, sizeof(buf)) <= 0 )
    {
        //log_err("ERROR: report temperature packet from socket failure\n");
        printf("ERROR: report temperature packet from socket failure\n");
        return -3;
    }
    printf("client write buf :%s\n");
    return 0;
}
